import asyncio
import functools
from datetime import datetime
from typing import List

import pywebio
from pywebio import  output
from emi.core.Runner import Runner, RunnerScheduler, RunnerContext
from emi.core.task import Task, TaskManager, TaskStatus
from emi.core.App import App
from emiui import UISession


class TaskUI:

    def __init__(self,app:App):
        self.runner_manager = app.getRunnerManager()
        self.task_manager = app.getTaskManager()
        self.app = app
        self.looper = None

    async def show(self):
        self.ui_session  = UISession.get(self.task_manager)
        #self.session_type = pywebio.session.get_session_implement()
        output.put_markdown("### Runner 列表")
        output.put_scope("_manager_runners")

        output.put_markdown("--------")
        output.put_markdown("### 注册Task列表")
        output.put_scope("_manager_task")

        output.put_markdown("--------")
        output.put_markdown("### 其他运行中的Task")
        output.put_scope("_other_running_task")

        await self._show_runners()
        await self._show_tasks()
        self.ui_session.task_changed_lisener = self._on_task_changed



    def _on_task_changed(self,task:Task):
        #print(f"id:{id(self)}:_on_task_changed,session id :{id(pywebio.session.get_current_session())}")
        #self._update_task(task)
        pywebio.session.run_async(self._update_task(task))
        #self.ui_session.post(self._update_task(task))
        # def _call_():
        #     self.session.run_async(self._update_task(task))
        # self.looper.call_soon(_call_)


    async def _show_runners(self):
        runners = self.runner_manager.get_runners()
        with output.use_scope("_manager_runners",clear=True):
            self._put_app_button()

            data_list = []
            data_list.append(["Runner名称"])
            for runner in runners:
                data_list.append([runner.getName()])
            output.put_table(data_list)

    async def _show_tasks(self):
        _tasks:List[Task] = self.task_manager.get_task_list()

        register_tasks = []
        other_running_tasks = []
        for _t in _tasks:
            if self.task_manager.has_register(_t):
                register_tasks.append(_t)
            elif _t.status.is_run():
                other_running_tasks.append(_t)


        with output.use_scope("_manager_task",clear=True):
            output.put_row([
                output.put_text("Task名称"),
                output.put_text("状态"),
                output.put_text(f"进度"),
                output.put_text(f"操作"),

            ])
            for task in register_tasks:
                assert task.id is not None
                output.put_scope(f"_task_id_{task.id}")
                await self._update_task(task)

        with output.use_scope("_other_running_task",clear=True):
            output.put_row([
                output.put_text("Task名称"),
                output.put_text("状态"),
                output.put_text(f"进度"),
                output.put_text(f"操作"),

            ])
            for task in other_running_tasks:
                assert task.id is not None
                output.put_scope(f"_task_id_{task.id}")
                await self._update_task(task)

    async def _update_task(self, task: Task):
        with output.use_scope(f"_task_id_{task.id}",clear=True):
            is_stop_action = task.status == TaskStatus.Running or task.status == TaskStatus.Waiting
            action_text = "停止" if is_stop_action else "开始"
            output.put_row([
                output.put_text(task.get_name()),
                output.put_text(task.status.value),
                output.put_text(f"{task.progress*100:.1f}%"),
                output.put_button(action_text, onclick=functools.partial(self.do_task_action,task, not is_stop_action))
            ])

    def do_task_action(self,task:Task,start_action:bool):
        if start_action:
            self.task_manager.run_task(task)
        else:
            self.task_manager.stop(task)



    def _put_app_button(self):
        app = self.app
        if not app.engine.is_running():
            def run_action():
                app.run()
                pywebio.session.run_async(self._show_runners())

            return output.put_button("启动", onclick=run_action)
        else:
            def stop_action():
                app.engine.stop()
                pywebio.session.run_async(self._show_runners())

            return output.put_button("停止", onclick=stop_action)



if __name__ == '__main__':
    from emi.core.App import App


    class MyRunner(Runner):

        def getName(self):
            return "MyRunner"

        def onStart(self, scheduler: RunnerScheduler):
            self.log("onStartUp")

            scheduler.run_weekly("3,4,6", "5:4:6", self.on_RunAt_Weekly_5_4_6, args={}, run_if_miss_time=True)
            scheduler.run_daily("15:23:34", self.onRunAt_15_23_34, args={}, run_if_miss_time=False)
            scheduler.run_daily("15:23:35", self.onRunAt_15_23_35, args={}, run_if_miss_time=False)

            scheduler.run_monthly("7,4,10,9,14", "1:11:11", self.on_RunAt_Monthly_1_11_11, args={},
                                  run_if_miss_time=False)

        def onRunAt_15_23_34(self):
            ##raise RuntimeError("sfsfsf")
            self.log("onRunAt_15_23_34")

        def onRunAt_15_23_35(self):
            pass

        def on_RunAt_Weekly_5_4_6(self):
            now = self.context.now();
            self.log(f"on_RunAt_Weekly_5_4_6, 星期{now.weekday() + 1}")
            self.context.post_delay(40, self.on_RunAt_Weekly_5_4_6_delay_at_40s)

        def on_RunAt_Weekly_5_4_6_delay_at_40s(self):
            self.log("on_RunAt_Weekly_5_4_6_delay_at_40s")

        def on_RunAt_Monthly_1_11_11(self):
            self.log("on_RunAt_Monthly_1_11_11")

        def onStop(self):
            self.log("onStop==>")
            pass


    class MyRunner2(Runner):

        def getName(self):
            return "MyRunner2"

        def onStart(self, scheduler: RunnerScheduler):
            self.log("onStartUp")
            self.count = 0
            scheduler.run_daily("15:23:34", self.onRunAt_15_23_34, args={}, run_if_miss_time=False)

        def onError(self, exception):
            self.log("onError=============")
            self.log("onError=============")
            self.log("onError=============")
            self.log("onError=============")
            app.getRunnerManager().cancel(MyRunner)

        def onRunAt_15_23_34(self):
            ##raise RuntimeError("sfsfsf")
            self.log("onXXXXXX=============")
            self.count += 1
            if self.count > 10:
                raise RuntimeError("hahahahah1")


    start = datetime(year=2021, month=1, day=12, hour=14)
    from time import sleep

    app = App()
    runnerManager = app.getRunnerManager()
    runnerManager.submit(MyRunner())
    runnerManager.submit(MyRunner2())

    class MyTaskUI(TaskUI):

        async def show(self):
            await super().show()
            task = self.task_manager.get_task_list()[1]
            self.ui_session.put_task(task)

    taskUI = MyTaskUI(app)

    class TaskDemo(Task):

        def __init__(self,name:str,second,has_error = False):
            self._name = name
            self.second = second
            self.has_error = has_error

        def get_name(self):
            return self._name

        def _run(self, context: RunnerContext):
            _start = datetime.now()
            while not context.check_stop():
                sleep(0.2)
                s = (datetime.now() - _start).total_seconds()
                self.progress = s / self.second
                if s  >= self.second:
                    break
            if self.has_error:
                raise  NotImplementedError()


    task_manager = app.getTaskManager()
    task_manager.register_task(TaskDemo("taskDemo01",3,False))
    task_manager.register_task(TaskDemo("taskDemo02",2,False))
    task_manager.register_task(TaskDemo("taskDemo_with_eeor",4,True))

    def hard_work(seconds):
        print(f"hard_work begin!")
        sleep(seconds)
        print(f"hard_work finish!")

    task_manager.run_in_thread(hard_work,(3))

    pywebio.start_server(functools.partial(MyTaskUI.show,taskUI),debug=True,port=8080)